import { Injectable, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs';
import { MotionDurationTime } from '../core/api';
import { LvSelectSM } from '../core/types';
import { CascaderFilter, CascaderOption, CascaderSearchOption } from './interface';

@Injectable()
export class CascaderService implements OnDestroy {
  searching = false;

  isLazyLoad = false;

  redraw$ = new Subject<void>();

  options: CascaderOption[] = [];

  open$ = new Subject<boolean>(); // 下拉面板展开收起流

  refresh$ = new Subject<void>();

  // 面板显示数据
  columns: CascaderOption[][] = [];
  resetStatus$ = new Subject<void>();
  searchColumns: CascaderSearchOption[][] = [];

  selectedOptions: CascaderOption[] | CascaderOption[][] = [];
  // 当前操作value
  _selection: Array<string | number> | Array<Array<string | number>> = [];

  selectionChange$ = new Subject<Array<string | number> | Array<Array<string | number>>>();
  private unfoldTimer;
  private mode: LvSelectSM = 'single';

  get selection(): any {
    return this._selection;
  }

  set selection(value: any) {
    if (Array.isArray(value) && Array.isArray(value[0])) {
      this._selection = value
        ? (value as any).map((item): Array<any> => item.filter((it): boolean => it !== undefined))
        : null;
    } else {
      this._selection = value ? (value as Array<any>).filter((item): boolean => item !== undefined) : null;
    }
    this.selectionChange$.next(this._selection);
  }

  getMode(): LvSelectSM {
    return this.mode;
  }

  closePanel(): void {
    this.open$.next(false);
  }

  setMode(value: LvSelectSM): void {
    this.mode = value;
  }

  isMultipleMode(): boolean {
    return this.mode === 'multiple';
  }

  isChildOption(o: CascaderOption): boolean {
    return o.isLeaf || !o.children?.length;
  }

  setSelectionBySearch(value): void {
    this.selectedOptions = value;
    this.selection = this.selectedOptions?.map((item): any => item.value);
  }

  ngOnDestroy(): void {
    this.redraw$.complete();
    this.selectionChange$.complete();
    this.open$.complete();
    this.resetStatus$.complete();
  }

  /**
   * 设置搜索结果的active状态
   * @param option
   */
  setSearchActive(option?): void {
    this.searchColumns.forEach((item): void => {
      this.clearActive(item.find((el): boolean => el.active));
    });

    if (option) {
      option.active = true;
    }
  }

  /**
   * 清空当前选项列中所有的active状态
   * @param option 状态为active的选项
   */
  clearActive(option: CascaderOption): void {
    if (!option) {
      return;
    }

    option.active = false;

    if (option.children) {
      this.clearActive(option.children.find((item): boolean => item.active));
    }
  }

  initOptions(options: CascaderOption[] = []): void {
    this.columns = [];
    this.options = [...options]; // NEED_DO 是否使用深拷贝

    this.options.forEach((option): void => {
      option.isRoot = true;
    });
    this.columns.push(this.options);
  }

  resetOptionStatus(option: CascaderOption[] = this.options): void {
    option.forEach((item): void => {
      if (!this.isMultipleMode()) {
        item.active = false;
      }
      item.selected = false;
      item.indeterminate = false;

      if (item.children) {
        this.resetOptionStatus(item.children);
      }
    });
  }

  setSelection(): void {
    // 单选
    const selectedOptions = [];
    this.columns.forEach((col): void => {
      const option = col.find((item): boolean => item.active);
      if (option) {
        selectedOptions.push(option);
      }
    });
    this.selectedOptions = selectedOptions;
    this.selection = this.selectedOptions?.map((item): any => item.value);
  }

  updateOptionsBySelection(): void {
    this.resetOptionStatus();
    if (this.isMultipleMode()) {
      (this._selection as any)?.forEach((item, index): void => {
        this.updateSinglePathBySelection(item, index === this._selection.length - 1);
      });
    } else {
      this.updateSinglePathBySelection(this._selection as Array<string | number>, true);
    }
  }

  /**
   * 展开当前选项
   * @param option 当前选项
   * @param index 选项的索引
   * @param lazyLoad 延迟加载
   * @param reload 重新加载
   */
  unfoldColumn(option: CascaderOption, index: number, lazyLoad: boolean): void {
    this.clearActive(this.columns[index].find((item): boolean => item.active));

    option.active = true;
    // 用于setTimeout变量判断, 删除动效完成时再push
    const lastLen = this.columns.length;
    this.columns.splice(index + 1); // 修改数组
    clearTimeout(this.unfoldTimer);
    this.unfoldTimer = setTimeout(
      (): void => {
        if (option.children?.length) {
          this.columns.push(option.children);
          this.redraw$.next();
        } else if (lazyLoad) {
          option.loading = true;
        }
      },
      index + 1 < lastLen ? MotionDurationTime.XS : 0,
    );
  }

  setMultiSelection(): void {
    const selectedOptions: CascaderOption[][] = [];
    const traversal = (node: CascaderOption, result: CascaderOption[]): void => {
      result.push(node);
      const children = node.children?.filter((item): boolean => item.selected);
      if (children?.length) {
        children.forEach((item): void => {
          traversal(item, [...result]);
        });
      } else {
        selectedOptions.push(result);
      }
    };
    this.columns[0]
      .filter((item): boolean => item.selected)
      .forEach((item): void => {
        traversal(item, []);
      });
    this.selectedOptions = selectedOptions;
    this.selection = this.selectedOptions?.map((item): any[] => item?.map((res): any => res.value));
  }

  updateSinglePathBySelection(selection: Array<string | number>, isActive = false): void {
    this.columns = [this.options];

    if (!selection?.length) {
      return;
    }

    for (let i = 0; i < selection.length; i++) {
      this.columns[i].forEach((item): false => (item.active = false));
      const target = this.columns[i]?.find((col): boolean => col.value === selection[i]);

      if (!target) {
        break;
      }

      target.active = isActive;
      target.selected = true;

      if (target.children?.length) {
        // 有子菜单展开子菜单
        this.columns.push(target.children);
      } else if (this.isLazyLoad) {
        // 懒加载没有子菜单的情况下，非叶子节点执行展开，叶子节点执行选中
        this.unfoldColumn(target, i, !target.isLeaf);
        break;
      }
    }
  }

  search(value: string): void {
    const results: CascaderSearchOption[] = [];
    const path: CascaderOption[] = [];

    this.searching = !!value;

    if (!this.columns.length) {
      return;
    }

    const defaultFilter: CascaderFilter = (val, p): boolean =>
      p.some((item): boolean => {
        const { label } = item;
        return !!label && label.toLowerCase().indexOf(val.toLowerCase()) !== -1;
      });

    const filter = defaultFilter; // NEED_DO: 自定义

    const loopChildren = (node: CascaderOption, forceDisabled = false): void => {
      path.push(node);
      const childPath = Array.from(path);

      if (filter(value.trim(), childPath)) {
        const disabled = forceDisabled || node.disabled;
        const option: CascaderSearchOption = {
          active: node.active,
          value: node.value,
          disabled,
          isLeaf: true,
          path: childPath,
          label: childPath.map((item): string => item.label).join(' / '),
        };

        results.push(option);
      }

      path.pop();
    };

    const loopParent = (node: CascaderOption, forceDisabled = false): void => {
      path.push(node);
      const disabled = forceDisabled || node.disabled;

      node.children?.forEach((item): void => {
        if (!item.parent) {
          item.parent = node;
        }

        if (!item.isLeaf) {
          loopParent(item, disabled);
        }

        if (this.isChildOption(item)) {
          loopChildren(item, disabled);
        }
      });

      path.pop();
    };

    this.columns[0].forEach((col): void => (this.isChildOption(col) ? loopChildren(col) : loopParent(col)));

    this.searchColumns = [results];

    this.redraw$.next();
  }
}
